From d18ba4e9dfe51e4689b510f954ba320bd21e3f32 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Fri, 6 Dec 2013 18:28:09 -0500 Subject: [PATCH] Add PPFrame::isVolatile and PPFrame::setVolatile Most wikitext is safe to parse once and then cache for when that same wikitext is used again, such as for multiple transclusions of the same template within a page. There are occasions, though, where some piece of wikitext has side effects and so should not be cached; a prominent example of such wikitext is the and tags in Cite.php. This change adds PPFrame::setVolatile so parser hooks such as and can indicate that they have done something that should not be cached, and PPFrame::isVolatile so that callers of PPFrame::expand can know when to avoid caching. Bug: 46815 Bug: 31834 Change-Id: I95b3cf8781cf047cdb63da221cef45f3e7d1632e --- RELEASE-NOTES-1.24 | 3 +++ includes/api/ApiExpandTemplates.php | 6 ++++- includes/parser/Parser.php | 6 +++-- includes/parser/Preprocessor.php | 24 ++++++++++++++++++ includes/parser/Preprocessor_DOM.php | 35 ++++++++++++++++++++++++--- includes/parser/Preprocessor_Hash.php | 35 ++++++++++++++++++++++++--- 6 files changed, 100 insertions(+), 9 deletions(-) diff --git a/RELEASE-NOTES-1.24 b/RELEASE-NOTES-1.24 index 6a6bcf798a..83ced70ef4 100644 --- a/RELEASE-NOTES-1.24 +++ b/RELEASE-NOTES-1.24 @@ -49,6 +49,9 @@ production. ATTENTION: This hook is likely to be removed soon due to overall design of the system. * (bug 17367) It is now possible to add pages to your watchlist from Special:UnwatchedPages without reloading the special page. +* New methods setVolatile and isVolatile are added to PPFrame, so that + extensions such as Cite.php can mark that their output is volatile and + shouldn't be cached. === Bug fixes in 1.24 === * (bug 49116) Footer copyright notice is now always displayed in user language diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php index 28ed5e48f7..b42a30b029 100644 --- a/includes/api/ApiExpandTemplates.php +++ b/includes/api/ApiExpandTemplates.php @@ -68,11 +68,15 @@ class ApiExpandTemplates extends ApiBase { ApiResult::setContent( $xml_result, $xml ); $result->addValue( null, 'parsetree', $xml_result ); } - $retval = $wgParser->preprocess( $params['text'], $title_obj, $options ); + $frame = $wgParser->getPreprocessor()->newFrame(); + $retval = $wgParser->preprocess( $params['text'], $title_obj, $options, null, $frame ); // Return result $retval_array = array(); ApiResult::setContent( $retval_array, $retval ); + if ( $frame->isVolatile() ) { + $retval_array['volatile'] = ''; + } $result->addValue( null, $this->getModuleName(), $retval_array ); } diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index cf174ec3f4..d0d29d388f 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -617,13 +617,15 @@ class Parser { /** * Expand templates and variables in the text, producing valid, static wikitext. * Also removes comments. + * Do not call this function recursively. * @param string $text * @param Title $title * @param ParserOptions $options * @param int|null $revid + * @param bool|PPFrame $frame * @return mixed|string */ - function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) { + function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null, $frame = false ) { wfProfileIn( __METHOD__ ); $magicScopeVariable = $this->lock(); $this->startParse( $title, $options, self::OT_PREPROCESS, true ); @@ -632,7 +634,7 @@ class Parser { } wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) ); wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) ); - $text = $this->replaceVariables( $text ); + $text = $this->replaceVariables( $text, $frame ); $text = $this->mStripState->unstripBoth( $text ); wfProfileOut( __METHOD__ ); return $text; diff --git a/includes/parser/Preprocessor.php b/includes/parser/Preprocessor.php index 25b34fa222..e7ccd104e8 100644 --- a/includes/parser/Preprocessor.php +++ b/includes/parser/Preprocessor.php @@ -165,6 +165,30 @@ interface PPFrame { */ function isTemplate(); + /** + * Set the "volatile" flag. + * + * Note that this is somewhat of a "hack" in order to make extensions + * with side effects (such as Cite) work with the PHP parser. New + * extensions should be written in a way that they do not need this + * function, because other parsers (such as Parsoid) are not guaranteed + * to respect it, and it may be removed in the future. + * + * @param bool $flag + */ + function setVolatile( $flag = true ); + + /** + * Get the "volatile" flag. + * + * Callers should avoid caching the result of an expansion if it has the + * volatile flag set. + * + * @see self::setVolatile() + * @return bool + */ + function isVolatile(); + /** * Get a title of frame * diff --git a/includes/parser/Preprocessor_DOM.php b/includes/parser/Preprocessor_DOM.php index 4f5ebc8041..dbbeddbf8c 100644 --- a/includes/parser/Preprocessor_DOM.php +++ b/includes/parser/Preprocessor_DOM.php @@ -983,6 +983,8 @@ class PPFrame_DOM implements PPFrame { */ var $depth; + private $volatile = false; + /** * @var array */ @@ -1485,6 +1487,24 @@ class PPFrame_DOM implements PPFrame { function getTitle() { return $this->title; } + + /** + * Set the volatile flag + * + * @param bool $flag + */ + function setVolatile( $flag = true ) { + $this->volatile = $flag; + } + + /** + * Get the volatile flag + * + * @return bool + */ + function isVolatile() { + return $this->volatile; + } } /** @@ -1552,10 +1572,14 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { * @return string */ function cachedExpand( $key, $root, $flags = 0 ) { - if ( !isset( $this->parent->childExpansionCache[$key] ) ) { - $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags ); + if ( isset( $this->parent->childExpansionCache[$key] ) ) { + return $this->parent->childExpansionCache[$key]; } - return $this->parent->childExpansionCache[$key]; + $retval = $this->expand( $root, $flags ); + if ( !$this->isVolatile() ) { + $this->parent->childExpansionCache[$key] = $retval; + } + return $retval; } /** @@ -1635,6 +1659,11 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { function isTemplate() { return true; } + + function setVolatile( $flag = true ) { + parent::setVolatile( $flag ); + $this->parent->setVolatile( $flag ); + } } /** diff --git a/includes/parser/Preprocessor_Hash.php b/includes/parser/Preprocessor_Hash.php index cb652ac18a..ad61eec91f 100644 --- a/includes/parser/Preprocessor_Hash.php +++ b/includes/parser/Preprocessor_Hash.php @@ -919,6 +919,8 @@ class PPFrame_Hash implements PPFrame { */ var $depth; + private $volatile = false; + /** * @var array */ @@ -1390,6 +1392,24 @@ class PPFrame_Hash implements PPFrame { function getTitle() { return $this->title; } + + /** + * Set the volatile flag + * + * @param bool $flag + */ + function setVolatile( $flag = true ) { + $this->volatile = $flag; + } + + /** + * Get the volatile flag + * + * @return bool + */ + function isVolatile() { + return $this->volatile; + } } /** @@ -1452,10 +1472,14 @@ class PPTemplateFrame_Hash extends PPFrame_Hash { * @return string */ function cachedExpand( $key, $root, $flags = 0 ) { - if ( !isset( $this->parent->childExpansionCache[$key] ) ) { - $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags ); + if ( isset( $this->parent->childExpansionCache[$key] ) ) { + return $this->parent->childExpansionCache[$key]; } - return $this->parent->childExpansionCache[$key]; + $retval = $this->expand( $root, $flags ); + if ( !$this->isVolatile() ) { + $this->parent->childExpansionCache[$key] = $retval; + } + return $retval; } /** @@ -1556,6 +1580,11 @@ class PPTemplateFrame_Hash extends PPFrame_Hash { function isTemplate() { return true; } + + function setVolatile( $flag = true ) { + parent::setVolatile( $flag ); + $this->parent->setVolatile( $flag ); + } } /** -- 2.20.1